package com.github.defense.plugin.gray.decision.factory;


import com.github.defense.plugin.gray.decision.GrayDecision;
import com.github.defense.plugin.gray.request.GrayHttpRequest;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Map;

/**
 * 基于指定字段按百分比放量进行判断
 *
 * @Author: lettger
 * @Date: 2021/6/23 12:24 下午
 */
@Slf4j
public class FlowRateGrayDecisionFactory extends AbstractGrayDecisionFactory<FlowRateGrayDecisionFactory.Config> {

    public FlowRateGrayDecisionFactory() {
        super(Config.class);
    }

    @Override
    public GrayDecision apply(Config config) {
        return args -> {
            log.debug("FlowRate Config:{}", config);
            GrayHttpRequest request = (GrayHttpRequest) args;
            String value = config.getType().getFieldValue(request, config.field);
            if (StringUtils.isEmpty(value)) {
                return false;
            }
            int hashcode;
            if (StringUtils.isNumeric(value)){
                hashcode = Integer.parseInt(value);
            }else {
                hashcode = Math.abs(value.hashCode());
            }
            int mod = hashcode % 100;
            log.debug("hashcode:{};mod:{}", hashcode, mod);
            return mod <= config.getRate();
        };
    }

    @Setter
    @Getter
    @ToString
    public static class Config {
        private FlowRateType type = FlowRateType.Header;
        private String field;
        private int rate;
    }

    public enum FlowRateType {
        /**
         * 基于Header 请求参数取值
         */
        Header {
            @Override
            public String getFieldValue(GrayHttpRequest request, String field) {
                return getValue(request.getHeaders(), field);
            }
        },
        /**
         * 基于url 参数取值
         */
        Parameter {
            @Override
            public String getFieldValue(GrayHttpRequest request, String field) {
                return getValue(request.getParameters(), field);
            }
        };

        public abstract String getFieldValue(GrayHttpRequest request, String field);

        public String getValue(Map<String, ? extends Collection<String>> map, String field) {
            Collection<String> collection = map.get(field);
            if (!CollectionUtils.isEmpty(collection)) {
                return StringUtils.join(collection, ",");
            }
            return null;
        }
    }
}
